/*
补充：
1.虚假唤醒
    wait（），notify-one（），notify-all（）
    比如，插入1条数据，但是唤醒了多次
    使第一次被唤醒后的wait（）实际没有做出相应的工作
    （因为第一次唤醒后，已经读出了1条数据，之后就没有数据了）

    本例中的解决方案很巧妙：
    在lambda表达式中，有一个判断很重要，保证了读取数据时，容器内一定有数据，防止了虚假唤醒
	所以在wait（）的第二个参数的函数/表达式内一定要加一句判断

2.atomic


3.线程池
常见设想：
	服务器程序：客户端    每次来一个客户端就创建一个线程给他服务
	网络游戏如果游戏人数特别多，如果仍然以线程的方式提供服务，就会导致线程过多，程序崩溃
	稳定性问题：编写代码时，偶尔创建一个线程这种代码，不安全
	于是出现了线程池，一个放了很多线程的池子，我们需要的时候在池子里拿线程，用完后放回池子
实现方式：在程序运行时，创建好线程

4.线程数量控制
	如果做某个技术开发，首先按照api提供商的要求创建
	如果是业务型，要不多不少，例如需要100个线程进行充值服务，那么我们的线程数量
	可以控制在110左右，在更大的范围内讲一般线程控制在500个以内
*/


#include<iostream>
#include<thread>
#include<vector>
#include <list>
#include<mutex>
using namespace std;

class A {
public:
	atomic<int> atm;
	A(){
		atm=0;
		//原子不可以赋值
		//错误提示为“尝试引用已删除的函数”表面原子内部的拷贝构造函数已经没有了
		//auto atm2=atm;
		//可以使用load（）进行原子的赋值
		atomic<int> atm2(atm.load());
		auto atm3(atm.load());
		//写入原子
		atm2.sotre(12);
		atm2=12;
		
	}
	//线程入口，读入消息队列
	void inMsgRecvQueue() {
		// for (int i = 0; i < 10000; ++i) {
		// 	cout << "inMsgRecvQueue()执行，插入一个元素" << i << endl;
		// 	unique_lock<mutex> my_guard(my_mutex, try_to_lock);
		// 	msgRecvQueue.push_back(i);
		// 	//...
		// 	//处理其他代码

		// 	//notify-one唤醒wait进程
		// 	//弊端：如果此时outMsgLULProc正在处理事务，并且消耗一段时间，
		// 	//而不是在wait（）处等待，则这个唤醒无效
		// 	my_condition.notify_one();
		// }
		// return;

		for (int i = 0; i < 10000; ++i) {
			atm+=1;

		}
		return;








	}


	//共享数据操作，提取到一个方法中
	bool outMsgLULProc(int &command) {
		//语法与lockguard类似


		//因为每次都要尝试加锁，效率较低
		//可以利用双重锁定来提高提高效率（外层加一层if (!msgRecvQueue.empty())
		//但是一直循环不是好的写法
		//我们希望消息队列不为空的时候，有东西去通知我们去取数据
		//用于condition-variable

		//unique_lock<mutex>(my_mutex);
		//if (!msgRecvQueue.empty()) {
		//	//消息不为空
		//	command = msgRecvQueue.front();
		//	msgRecvQueue.pop_front();
		//	return true;
		//}
		//else {
		//	return false;
		//}

	}

	//线程入口，取出消息队列
	void outMsgRecvQueue() {

		//int command = 0;
		// while (true) {
		// 	unique_lock<mutex> sbguard(my_mutex);
		// 	//wait(uniquelock对象，lambda表达式/函数对象）
		// 	//判断释放为空，可以处理虚假唤醒
		// 	my_condition.wait(sbguard, [this] {
		// 		if (!msgRecvQueue.empty())
		// 		{
		// 			return true;
		// 		}
		// 		return false;
		// 		}
		// 	);
		// 	//程序经过这一步，互斥锁一定是锁着的
		// 	//此时我们可以输出数据并解锁，以便其他线程使用共享数据
		// 	command = msgRecvQueue.front();
		// 	msgRecvQueue.pop_front();
		// 	sbguard.unlock();
		// 	cout << "取出元素" << command << endl;


	while (true) {
		//读atm的值是原子操作，但是整个这行代码不是原子操作
		//也就是说，屏幕显示的值和不一定是atm真正的值
		cout<<atm<<endl;

	}

		}



		//for (int i = 0; i < 100000; ++i) {
		//	if (outMsgLULProc(command)) {
		//		//具体操作
		//		cout << "具体操作,取出一个元素" << command << endl;
		//	}
		//	else {
		//		cout << "消息为空" << i << endl;
		//	}
		//}
		//cout << "消息处理结束" << endl;
	}

private:
	list<int> msgRecvQueue;
	mutex my_mutex;
	//创建一个条件变量对象
	condition_variable my_condition;

};

int main(int argc,char** argc){


	A myobja;
	thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
	thread myInMsgObj2(&A::inMsgRecvQueue, &myobja);
	myOutMsgObj.join();
	myInMsgObj.join();
	myInMsgObj2.join();


    return 0;
}